/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.contract.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.common.customize.enums.CommonDictEnum;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.customize.security.utils.SecurityUtil;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.contract.constant.ContractMqConstants;
import com.pig4cloud.pigx.contract.constant.I18nMessages;
import com.pig4cloud.pigx.contract.dto.ContractOrderCancelDTO;
import com.pig4cloud.pigx.contract.dto.ContractOrderCloseByPositionDTO;
import com.pig4cloud.pigx.contract.dto.ContractOrderCloseDTO;
import com.pig4cloud.pigx.contract.dto.ContractOrderCloseMarketDTO;
import com.pig4cloud.pigx.contract.dto.ContractOrderNewDTO;
import com.pig4cloud.pigx.contract.dto.ContractOrderOpenDTO;
import com.pig4cloud.pigx.contract.dto.ContractRobotPlaceOrderDTO;
import com.pig4cloud.pigx.contract.entity.ContractOrder;
import com.pig4cloud.pigx.contract.entity.ContractPosition;
import com.pig4cloud.pigx.contract.enums.ContractOrderEnum;
import com.pig4cloud.pigx.contract.enums.ContractPositionEnum;
import com.pig4cloud.pigx.contract.executer.order.OrderExecutor;
import com.pig4cloud.pigx.contract.mapper.ContractOrderMapper;
import com.pig4cloud.pigx.contract.mapper.ContractPositionMapper;
import com.pig4cloud.pigx.contract.mapstruct.ContractOrderStruct;
import com.pig4cloud.pigx.contract.service.ContractOrderService;
import com.pig4cloud.pigx.contract.utils.ContractUtils;
import lombok.AllArgsConstructor;
import org.apache.logging.log4j.util.Strings;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 订单表
 *
 * @since 2022-08-11 10:08:11
 */
@Service
@AllArgsConstructor
public class ContractOrderServiceImpl extends ServiceImpl<ContractOrderMapper, ContractOrder> implements ContractOrderService {

    private final ContractPositionMapper contractPositionMapper;

    private final OrderExecutor orderExecutor;
    private final AmqpTemplate rabbit;
    private final ContractUtils contractUtils;

    /**
     * 开仓
     *
     * @param dto dto
     * @since 2022/8/16 18:08
     */
    @Override
    public void open(ContractOrderOpenDTO dto) {
        ContractOrderNewDTO newDTO = ContractOrderStruct.INSTANCE.openDTO2NewDTO(dto);
        PigxUser user = SecurityUtil.getLoginUserNotNull();
        newDTO.setUserId(user.getId());
        newDTO.setOperationType(ContractOrderEnum.OperationType.OPEN.getValue());
        newDTO.setIsRobot(CommonDictEnum.YesOrNo.NO.getValue());
        orderExecutor.init(newDTO);
    }

    /**
     * 平仓
     *
     * @param dto dto
     * @since 2022/9/6 14:38
     */
    @Override
    public void close(ContractOrderCloseDTO dto) {
        orderExecutor.close(dto);
    }

    /**
     * 市价全平接口
     *
     * @param dto dto
     * @since 2023/2/28 15:24
     */
    @Override
    public void closeMarket(ContractOrderCloseMarketDTO dto) {
        // 判断入参
        if (Objects.isNull(dto.getPositionId())
                && (Strings.isBlank(dto.getSymbolName())
                || Strings.isBlank(dto.getPositionMode())
                || Strings.isBlank(dto.getSide()))) {
            throw new RuntimeException(MessageUtils.get(I18nMessages.DATA_IS_EMPTY));
        }

        PigxUser user = SecurityUtil.getLoginUserNotNull();

        // 查询仓位信息
        ContractPosition condition = new ContractPosition();
        condition.setId(dto.getPositionId());
        // 确保是本人的仓位
        condition.setUserId(user.getId());
        condition.setSymbolName(dto.getSymbolName());
        condition.setMode(dto.getPositionMode());
        condition.setSide(dto.getSide());
        ContractPosition position = contractUtils.getOneCurrentPosition(condition, false);
        // 校验仓位信息
        ContractUtils.checkCurrentPosition(position, false);

        ContractOrderCloseByPositionDTO closeDTO = new ContractOrderCloseByPositionDTO();
        closeDTO.setPositionId(position.getId());
        closeDTO.setClientOrderId(dto.getClientOrderId());
        orderExecutor.closeByPosition(closeDTO);
    }

    /**
     * 市价全平
     *
     * @since 2022/9/6 18:37
     */
    @Override
    public void closeAll() {
        PigxUser user = SecurityUtil.getLoginUserNotNull();

        // 查询当前用户所有需要平仓的仓位
        QueryWrapper<ContractPosition> query = new QueryWrapper<>();
        query.lambda()
                .select(ContractPosition::getId)
                .eq(ContractPosition::getUserId, user.getId())
                .eq(ContractPosition::getNeedLiquidate, CommonDictEnum.YesOrNo.NO.getValue())
                .in(ContractPosition::getStatus, ContractPositionEnum.Status.OPEN.getValue(),
                        ContractPositionEnum.Status.PARTIAL_CLOSE.getValue());

        List<ContractPosition> positionList = contractPositionMapper.selectList(query);

        // 发送mq消息
        ContractOrderCloseByPositionDTO closeDTO = new ContractOrderCloseByPositionDTO();
        positionList.forEach(i -> {
            closeDTO.setPositionId(i.getId());
            rabbit.convertAndSend(ContractMqConstants.EXCHANGE_FANOUT_CONTRACT_POSITION_CLOSE_ALL,
                    null,
                    closeDTO);
        });
    }

    /**
     * 撤销单个订单
     *
     * @param id id
     * @since 2022/8/25 11:26
     */
    @Override
    public void cancel(Long id) {
        PigxUser user = SecurityUtil.getLoginUserNotNull();
        ContractOrderCancelDTO dto = new ContractOrderCancelDTO();
        dto.setId(id);
        dto.setUserId(user.getId());
        orderExecutor.cancel(dto);
    }

    /**
     * 撤销当前用户全部订单
     *
     * @since 2022/9/3 21:40
     */
    @Override
    public void cancelAll() {
        PigxUser user = SecurityUtil.getLoginUserNotNull();
        orderExecutor.cancelByUser(user.getId());
    }

    @Override
    public Integer getTransactionUser() {
        return baseMapper.getTransactionUser();
    }

    /**
     * 批量新增订单-kLine机器人
     *
     * @param dtoList dtoList
     * @since 2022/8/31 14:22
     */
    @Override
    public void newOrderMultiRobotKLine(List<ContractRobotPlaceOrderDTO> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }

        // 转换对象
        List<ContractOrderNewDTO> list = ContractOrderStruct.INSTANCE.orderNewRobotKLineDTOList2OrderNewDTOList(dtoList);
        // 遍历
        list.forEach(i -> {
            // 初始化数据
            i.setType(ContractOrderEnum.Type.LIMIT.getValue());
            i.setOperationType(ContractOrderEnum.OperationType.OPEN.getValue());
            i.setPositionMode(ContractPositionEnum.Mode.ISOLATED.getValue());
            i.setMultiple(1);
            i.setPositionId(0L);
            i.setIsRobot(CommonDictEnum.YesOrNo.YES.getValue());
            i.setMargin(BigDecimal.ZERO);
            i.setHasStopProfit(CommonDictEnum.YesOrNo.NO.getValue());
            i.setHasStopLost(CommonDictEnum.YesOrNo.NO.getValue());

            // 调用OrderExecutor
            orderExecutor.init(i);
        });
    }
}
